﻿using System;
using System.Drawing;
using System.Windows.Forms;
using SDK;

namespace ThermoGroupSample {
    public partial class FormVisible : Form {
        private FormInfrared mFormInfrared;
        private MagDevice mDevice;

        // Delegate
        private GroupSDK.DelegateVisNewFrame mNewFrameDelegate;
        private GroupSDK.DelegateVisReconnect mReconnectDelegate;
        private GroupSDK.DelegateVisInitialize mInitializeDelegate;

        private int mVideoWidth;
        private int mVideoHeight;
        private Rectangle mIrMappedVisRect;

        private bool mIsVisibleSupported = true;

        public FormVisible() {
            InitializeComponent();
        }

        // set object reco callback
        public void bindInfrared(FormInfrared formInfrared) {
            mFormInfrared = formInfrared;
        }

        public void bindDevice(MagDevice device) {
            mDevice = device;
        }

        public bool play(string ip) {
            if (mDevice == null || !mDevice.IsLinked()) {
                return false;
            }

            mIrMappedVisRect = getIrMappedVisField();

            var regContent = mDevice.GetRegContent();
            if (regContent.intPartnerVisibleIp == 0) {
                // visible is not supported by this camera
                mIsVisibleSupported = false;
                Invalidate(false);
                return false;
            }

            mIsVisibleSupported = true;

            mInitializeDelegate = new GroupSDK.DelegateVisInitialize(beforeNewFrameCome);
            mNewFrameDelegate = new GroupSDK.DelegateVisNewFrame(newFrameCome);
            mReconnectDelegate = new GroupSDK.DelegateVisReconnect(reconnectNotify);

            mDevice.VisSetInitCallback(mInitializeDelegate, IntPtr.Zero);
            mDevice.VisSetReconnectCallback(mReconnectDelegate, IntPtr.Zero);

            string rtsp = "rtsp://" + ip + ":554/camera1";
            if (mDevice.VisPlay(rtsp, GroupSDK.VideoPixFormat.pixFmtARGB, mNewFrameDelegate, IntPtr.Zero, 1, 3000) != 0) { // only support ARGB now
                return false;
            }

            mVideoWidth = mDevice.VisGetWidth();
            mVideoHeight = mDevice.VisGetHeight();

            return true;
        }

        public bool saveBMP() {
            if (mDevice == null) {
                return false;
            }
            return mDevice.VisSaveBMP("vis.bmp") == 0;
        }

        public void stop() {
            // mDevice.VisStop() is called in FormInfrared::stop(), it must 
            // be called before mDevice.DisLinkCamera()
            if (mDevice.VisIsPlaying()) {
                mDevice.VisStop();
            }

            mIsVisibleSupported = true;
            Invalidate(false);
        }

        private void beforeNewFrameCome(uint hDevice, int width, int height, IntPtr pUserData) {
            // For initialize before visible streaming
        }

        private void newFrameCome(uint hDevice, byte[] data, int width, int height, int pixelFormat, IntPtr pUserData) {
            Invalidate(false);
        }

        private void reconnectNotify(uint hDevice, int status, IntPtr pUserData) {
            if (status == 0) {
                // reconnect succ
            } else if (status == 1) {
                // reconnecting
            } else {
                // reconnect succ
            }
        }

        private void FormVisible_Paint(object sender, PaintEventArgs e) {
            if (mDevice == null) {
                return;
            }

            Graphics graphic = e.Graphics;

            if (!mIsVisibleSupported) {
                graphic.DrawString("该热像仪不支持可见光", new Font("宋体", 10, FontStyle.Bold), Brushes.Red, new Point(120, 150));
            } else if (!mDevice.VisIsPlaying()) {
                return;
            }

            Bitmap bitmap = null;

            // get vis data with lock(only lock() can ensure that all data got in the same frame)
            mDevice.VisLock();
            bitmap = mDevice.VisGetBitmap();
            mDevice.VisUnlock();

            // draw visible
            if (bitmap != null) {
                graphic.DrawImage(bitmap, new Rectangle(0, 0, Width, Height), 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel);
            }

            drawDetectObjs(graphic, Width, Height);
            drawIrMappedVisField(graphic, Width, Height);
        }

        //////////////// object detect related //////////////////////////

        private void drawDetectObjs(Graphics graphic, int width, int height) {
            GroupSDK.CAMERA_INFO camInfo = mDevice.GetCamInfo();
            Pen pen = new Pen(Brushes.LightGreen, 2);
            Font font = new Font("宋体", 10, FontStyle.Bold);
            Brush brush = new SolidBrush(Color.LightGreen);

            lock (mFormInfrared.mRecoLock) {
                for (uint i = 0; i < mFormInfrared.mRecObjNum; i++) {
                    GroupSDK.OBJ_INFO roi = mFormInfrared.mObjInfo[i];

                    // get object region on screen
                    Point pt0 = Util.axesTransfer(roi.rectVis.left, roi.rectVis.top, mVideoWidth, mVideoHeight, width, height);
                    Point pt1 = Util.axesTransfer(roi.rectVis.right, roi.rectVis.bottom, mVideoWidth, mVideoHeight, width, height);

                    int x0 = pt0.X, y0 = pt1.Y, x1 = pt1.X, y1 = pt0.Y;

                    // draw object region
                    graphic.DrawRectangle(pen, x0, y0, x1 - x0, y1 - y0);

                    // get max temp position on screen
                    int fpaY = roi.shortSamplePointVisY;
                    int fpaX = roi.shortSamplePointVisX;
                    int x = Util.axesTransfer(fpaX, fpaY, mVideoWidth, mVideoHeight, width, height).X;
                    int y = Util.axesTransfer(fpaX, fpaY, mVideoWidth, mVideoHeight, width, height).Y;//默认右上

                    // draw cursor
                    int halfLen = 4;
                    Point pt = Util.axesTransfer(fpaX, fpaY, mVideoWidth, mVideoHeight, width, height);
                    graphic.DrawLine(pen, pt.X - halfLen, pt.Y, pt.X + halfLen, pt.Y);
                    graphic.DrawLine(pen, pt.X, pt.Y - halfLen, pt.X, pt.Y + halfLen);

                    // draw temp
                    int intTemp = roi.intBodyTemp;
                    string sText = (intTemp * 0.001f).ToString("0.0");
                    graphic.DrawString(sText, font, brush, x0, y0 - 15);
                }
            }
        }

        private void drawIrMappedVisField(Graphics graphic, int width, int height) {
            if (mIrMappedVisRect.IsEmpty) {
                return;
            }

            int x = mIrMappedVisRect.Left * width / mVideoWidth;
            int y = height - 1 - mIrMappedVisRect.Bottom * height / mVideoHeight;
            int w = mIrMappedVisRect.Width * width / mVideoWidth;
            int h = mIrMappedVisRect.Height * height / mVideoHeight;

            Pen pen = new Pen(Brushes.LightGreen, 2);
            pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Custom;
            pen.DashPattern = new float[] { 1f, 1f };
            graphic.DrawRectangle(pen, x, y, w, h);
        }

        private Rectangle getIrMappedVisField() {
            GroupSDK.CAMERA_INFO camInfo = mDevice.GetCamInfo();

            //获取与红外图像中四个顶点,相对应的可见光中的四个顶点坐标
            int x00 = 0, x01 = 0, x10 = 0, x11 = 0, y00 = 0, y01 = 0, y10 = 0, y11 = 0;
            bool b1 = mDevice.ConvertIrCorr2VisCorr(0, 0, 0.0f, ref x00, ref y00);
            bool b2 = mDevice.ConvertIrCorr2VisCorr(0, camInfo.intFPAHeight - 1, 0.0f, ref x01, ref y01);
            bool b3 = mDevice.ConvertIrCorr2VisCorr(camInfo.intFPAWidth - 1, 0, 0.0f, ref x10, ref y10);
            bool b4 = mDevice.ConvertIrCorr2VisCorr(camInfo.intFPAWidth - 1, camInfo.intFPAHeight - 1, 0.0f, ref x11, ref y11);
            if (!b1 || !b2 || !b3 || !b4) {
                return new Rectangle();
            }

            int left = Math.Min(x00, x01);
            int top = Math.Min(y00, y10);
            int right = Math.Max(x10, x11);
            int bottom = Math.Max(y01, y11);

            Util.makeValueInRange(ref left, 0, mVideoWidth - 1);
            Util.makeValueInRange(ref top, 0, mVideoHeight - 1);
            Util.makeValueInRange(ref right, 0, mVideoWidth - 1);
            Util.makeValueInRange(ref bottom, 0, mVideoHeight - 1);

            return new Rectangle(left, top, right - left + 1, bottom - top + 1);
        }
    }
}
